home *** CD-ROM | disk | FTP | other *** search
/ APDL Eductation Resources / APDL Eductation Resources.iso / programs / electronic / rlab / !RLaB / misc / plplot < prev    next >
Encoding:
Text File  |  1995-03-05  |  55.5 KB  |  2,539 lines

  1. #
  2. # New plot.r for use with PLPLOT library.
  3. # The help files for these functions are in
  4. # misc/plhelp
  5. #
  6.  
  7. # plplot.r
  8.  
  9. # This file is a part of RLaB ("Our"-LaB)
  10. # Copyright (C) 1994  Ian R. Searle
  11.  
  12. # This program is free software; you can redistribute it and/or modify
  13. # it under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation; either version 2 of the License, or
  15. # (at your option) any later version.
  16.  
  17. # This program is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. # GNU General Public License for more details.
  21.  
  22. # You should have received a copy of the GNU General Public License
  23. # along with this program; if not, write to the Free Software
  24. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26. # See the file ../COPYING
  27.  
  28. #
  29. # If your system does not deal with Infs and NaNs well, then
  30. # uncomment the following lines.
  31. #
  32.  
  33. # static (isinf, isnan)
  34. #
  35. # isinf = function ( A ) { return (0); };
  36. # isnan = function ( A ) { return (0); };
  37.  
  38. static (WIN)        # The static plot window structure
  39. static (P)        # The active/current plot window
  40.  
  41. #
  42. # Maintain the transformations for 3-D plots.
  43. #
  44.  
  45. static (basex, basey, height)
  46. basex = 2;
  47. basey = 2;
  48. height = 4;
  49.  
  50. #
  51. # Static (private) functions. For use from within
  52. # this file only.
  53. #
  54.  
  55. static (create_plot_object)
  56. static (check_plot_object)
  57. static (xy_scales)
  58. static (x_scales)
  59. static (y_scales)
  60. static (z_scales)
  61. static (XYZ_scales)
  62. static (list_scales)
  63. static (list_sort)
  64. static (hist_scales)
  65. static (plot_matrix)
  66. static (plot_list)
  67. static (check_3d_list)
  68. static (find_char)
  69. static (get_style)
  70. static (make_legend)
  71. static (plhold_first)
  72.  
  73. #
  74. # Defaults
  75. #
  76.  
  77. static (grid_x_default, grid_y_default)
  78. static (grid_3x_default, grid_3y_default, grid_3z_default)
  79.  
  80. grid_x_default = "bcnst";
  81. grid_y_default = "bcnstv";
  82. grid_3x_default = "bnstu";
  83. grid_3y_default = "bnstu";
  84. grid_3z_default = "bcdmnstuv";
  85.  
  86. static (subplot_f)
  87. subplot_f = 0;
  88.  
  89. #
  90. # Create the default plot-object.
  91. # Initialize to all the default values
  92. #
  93.  
  94. if (!exist (WIN)) 
  95. {
  96.   # Create the plot-object list
  97.   WIN = <<>>;
  98. }
  99.  
  100. create_plot_object = function ( N, nx, ny )
  101. {
  102.   if (!exist (N)) { N = 0; }
  103.   
  104.   pobj = <<>>;
  105.   pobj.subplot = 0;        # The current subplot no.
  106.   pobj.nplot = nx*ny;        # Total no. of plots on window
  107.   
  108.   pobj.fontld = 0;        # Loaded extended fonts?
  109.   
  110.   for (i in 1:(nx*ny))
  111.   {
  112.     pobj.style.[i] = "line";    # The type/style of plot to draw
  113.     pobj.pstyle[i] = 1;            # The point-style
  114.     pobj.nbin[i] = 1j;          # The number of bins for a histogram
  115.     pobj.width[i] = 1;        # The pen width for current plot
  116.     pobj.font[i] = 1;        # The current font
  117.     pobj.xlabel[i] = "";
  118.     pobj.ylabel[i] = "";
  119.     pobj.zlabel[i] = "";
  120.     pobj.title[i] = "";
  121.     pobj.orientation[i] = "portrait";
  122.     pobj.desc.[i] = "default";        # The legend description
  123.     pobj.gridx[i] =  grid_x_default;    # Plot axes style, 2D-X
  124.     pobj.gridy[i] =  grid_y_default;    # Plot axes style, 2D-Y
  125.     pobj.grid3x[i] = grid_3x_default;    # Plot axes style, 3D-X
  126.     pobj.grid3y[i] = grid_3y_default;    # Plot axes style, 3D-Y
  127.     pobj.grid3z[i] = grid_3z_default;    # Plot axes style, 3D-Z
  128.     pobj.aspect[i] = 0;                # Plot aspect style
  129.     pobj.alt[i] = 60;
  130.     pobj.az[i] = 45;
  131.     
  132.     pobj.xmin[i] = 1j;
  133.     pobj.xmax[i] = 1j;
  134.     pobj.ymin[i] = 1j;
  135.     pobj.ymax[i] = 1j;
  136.     pobj.zmin[i] = 1j;
  137.     pobj.zmax[i] = 1j;
  138.     
  139.     pobj.page.xp = 0;
  140.     pobj.page.yp = 0;
  141.     pobj.xleng = 400;
  142.     pobj.yleng = 300;
  143.     pobj.xoff = 200;
  144.     pobj.yoff = 200;
  145.  
  146.     for (j in 1:14) { pobj.color[i;j] = j; }       
  147.     for (j in 1:8)  { pobj.lstyle[i;j] = j; }
  148.   }
  149.   
  150.   #
  151.   # Save the newly generated plot-object
  152.   # in a list of plot-objects.
  153.   
  154.   WIN.[N] = pobj;
  155. };
  156.  
  157. ##############################################################################
  158. #
  159. # Check to make sure a plot-object exists. If one
  160. # does not exist, create it.
  161. #
  162.  
  163. check_plot_object = function ()
  164. {
  165.   if (length (WIN) == 0)
  166.   {
  167.     pstart();
  168.     return 0;
  169.   }
  170.   return 1;
  171. };
  172.  
  173. ##############################################################################
  174. #
  175. # Set the current plot window
  176. # Default value = 0
  177. #
  178.  
  179. pwin = function ( N )
  180. {
  181.   check_plot_object ();
  182.   if (!exist (N)) { N = 0; }
  183.   
  184.   # Check to make sure N is valid
  185.   
  186.   for (i in members (WIN))
  187.   {
  188.     if (N == strtod (i))
  189.     {
  190.       _plsstrm (N);
  191.       return P = N;
  192.     }
  193.   }
  194.   printf ("pwin: invalid argument, N = %i\n", N);
  195.   printf ("      valid values are:\n");
  196.   WIN?
  197. };
  198.  
  199. ##############################################################################
  200. #
  201. # Show the current plot-window, and the possibilities
  202. #
  203.  
  204. showpwin = function ( all )
  205. {
  206.   if (length (WIN) == 0)
  207.   {
  208.     printf ("No plot objects\n");
  209.     return 0;
  210.   }
  211.   
  212.   printf ("Current plot-window is:\t\t%i\n", P);
  213.   printf ("Available plot windows are:\t");
  214.   for (i in members (WIN))
  215.   {
  216.     printf ("%s   ", i);
  217.   }
  218.   printf ("\n");
  219.  
  220.   if (exist (all))
  221.   {
  222.     for (i in members (WIN.[P]))
  223.     {
  224.       WIN.[P].[i]
  225.     }
  226.   }
  227. };
  228.  
  229. getplot = function ( win_no )
  230. {
  231.   local (win_no)
  232.  
  233.   if (length (WIN) != 0)
  234.   {
  235.     if (!exist (win_no)) { win_no = P; }
  236.  
  237.     if (exist (WIN.[win_no]))
  238.     {
  239.       return (WIN.[win_no]);
  240.     else
  241.       return 0;
  242.     }
  243.   }
  244.   return <<>>;
  245. };
  246.  
  247.  
  248. ##############################################################################
  249. #
  250. # Set/start/select the plot device
  251. #
  252.  
  253. pstart = function ( nx, ny, dev )
  254. {
  255.   if (!exist (nx)) { nx = 1; }
  256.   if (!exist (ny)) { ny = 1; }
  257.   if (!exist (dev)) { dev = "?"; }
  258.   
  259.   # Create the plot-object
  260.   # First, figure out the index
  261.   if (!exist (P))
  262.   {
  263.     P = 0;
  264.   else
  265.     P = P + 1;
  266.   }
  267.   
  268.   create_plot_object (P, nx, ny);
  269.   _plsstrm (P);
  270.   
  271.   #_plscolbg (255,255,255); # white
  272.   # Default window size for X
  273.   _plspage (0, 0, 400, 300, 200, 200);
  274.   
  275.   # Start up the plot-window
  276.   _plstart (dev, nx, ny);
  277.   
  278.   _plwid (8);
  279.   
  280.   # Turn between plot pause off
  281.   _plspause (0);
  282.   _pltext ();
  283.   
  284.   return P;
  285. };
  286.  
  287. ##############################################################################
  288. #
  289. # Close a plot device. We must destroy the current plot-object
  290. # And switch the output stream back to the default.
  291. #
  292.  
  293. pclose = function ()
  294. {
  295.   if (size (WIN) > 1)
  296.   {   
  297.     #
  298.     # Clear WIN.[P] and reset P to 1st plot-window
  299.     #
  300.  
  301.     clear (WIN.[P]);
  302.     _plend1 ();
  303.     _plsstrm (strtod (members (WIN)[1]));
  304.     P = strtod (members (WIN)[1]);
  305.     return P;
  306.  
  307.   else if (size (WIN) == 1) {
  308.  
  309.     if (exist (WIN.[P])) 
  310.     { 
  311.       clear (WIN.[P]); 
  312.       clear (P);
  313.     }
  314.     _plend1 ();
  315.     return 1;
  316.  
  317.   else if (size (WIN) == 0) {
  318.  
  319.     return 0;
  320.  
  321.   } } }
  322. };
  323.  
  324. ##############################################################################
  325. #
  326. # Close ALL the plot-windows
  327. #
  328.  
  329. pend = function ()
  330. {
  331.   _plend ();
  332.   if (exist (WIN)) { clear (WIN); }
  333.   if (exist (P)) { clear (P); }
  334.   WIN = <<>>;
  335. };
  336.  
  337. ##############################################################################
  338. #
  339. # Change plot aspect ratio
  340. #
  341.  
  342. plaspect = function ( aspect )
  343. {
  344.   check_plot_object ();
  345.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  346.   if (!exist (aspect))
  347.   {
  348.     WIN.[P].aspect[i] = 0;
  349.   else
  350.     WIN.[P].aspect[i] = aspect;
  351.   }
  352. };
  353.  
  354. ##############################################################################
  355. #
  356. # Change plot line style
  357. #
  358.  
  359. plstyle = function ( style )
  360. {
  361.   check_plot_object ();
  362.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  363.  
  364.   if (exist (style)) 
  365.   {
  366.     if (class (style) == "string") 
  367.     {
  368.       WIN.[P].style.[i] = style;
  369.     }
  370.     return 1;
  371.   }
  372.   WIN.[P].style.[i] = "line";  
  373. };
  374.  
  375. ##############################################################################
  376. #
  377. # Get the right value of line-style
  378. #
  379.  
  380. get_style = function ( STY, K )
  381. {
  382.   local (sty);
  383.   sty = mod(K, STY.n);
  384.   if(sty == 0) 
  385.   { 
  386.     sty = STY.n; 
  387.   }
  388.   return STY[sty];
  389. };
  390.  
  391. ##############################################################################
  392. #
  393. # Change fonts
  394. #
  395.  
  396. plfont = function ( font )
  397. {
  398.   check_plot_object ();
  399.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  400.   
  401.   if (!exist (font)) { font = 1; }
  402.   
  403.   if (WIN.[P].fontld == 0)
  404.   {
  405.     _plfontld (1);
  406.     WIN.[P].fontld = 1;
  407.   }
  408.   
  409.   WIN.[P].font[i] = font;
  410.   return P;
  411. };
  412.  
  413. ##############################################################################
  414. #
  415. # Change pen width
  416. #
  417.  
  418. plwid = function ( width )
  419. {
  420.   check_plot_object ();
  421.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  422.   
  423.   if (!exist (width)) { width = 1; }
  424.   WIN.[P].width[i] = width;
  425.   return P;
  426. };
  427.  
  428. ##############################################################################
  429. #
  430. # Place some text on the plot
  431. #
  432.  
  433. plptex = function ( text, x , y , dx , dy , just )
  434. {
  435.   if (!check_plot_object ()) 
  436.   {
  437.     printf ("Must use plot() before plptex()\n");
  438.     return 0;
  439.   }
  440.   
  441.   if (!exist (x)) { x = 0; }
  442.   if (!exist (y)) { y = 0; }
  443.   if (!exist (dx)) { dx = abs(x)+1; }
  444.   if (!exist (dy)) { dy = 0; }
  445.   if (!exist (just)) { just = 0; }
  446.   
  447.   _plptex (x, y, dx, dy, just, text);
  448. };
  449.  
  450. ##############################################################################
  451. #
  452. # Set up the viewing altitude for 3-D plots
  453. #
  454.  
  455. plalt = function ( ALT )
  456. {
  457.   check_plot_object ();
  458.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  459.  
  460.   if (exist (ALT)) 
  461.   { 
  462.     WIN.[P].alt[i] = ALT; 
  463.   else
  464.     WIN.[P].alt[i] = 60;
  465.   }
  466.   return P;
  467. };
  468.  
  469. ##############################################################################
  470. #
  471. # Set the viewing azimuth for 3-D plots
  472. #
  473.  
  474. plaz = function ( AZ )
  475. {
  476.   check_plot_object ();
  477.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  478.  
  479.   if (exist (AZ)) 
  480.   { 
  481.     WIN.[P].az[i] = AZ; 
  482.   else
  483.     WIN.[P].az[i] = 45;
  484.   }
  485.   return P;
  486. };
  487.  
  488. ##############################################################################
  489. #
  490. # Find a character in a string
  491. #
  492.  
  493. find_char = function ( str , char )
  494. {  
  495.   tmp = strsplt (str);
  496.   for (i in 1:tmp.n)
  497.   {
  498.     if (tmp[i] == char) 
  499.     {
  500.       return i;
  501.     }
  502.   }
  503.   return 0;
  504. };
  505.  
  506. ##############################################################################
  507. #
  508. # Sort list element names/labels by numeric order, then string order.
  509. #
  510.  
  511. list_sort = function ( L )
  512. {
  513.   tl = <<>>;
  514.   j = k = 1;
  515.  
  516.   for (i in members (L))
  517.   {
  518.     if (!isnan (strtod (i)))
  519.     {
  520.       num[j] = i;
  521.       j++;
  522.       else
  523.       char[k] = i;
  524.       k++;
  525.     }
  526.   }
  527.   
  528.   # Sort the numeric labels
  529.   
  530.   if (exist (num))
  531.   {
  532.     num = sort (strtod (num)).val;
  533.     tl.num = num;
  534.   }
  535.  
  536.   if (exist (char))
  537.   {
  538.     tl.char = char;
  539.   }
  540.  
  541.   return tl;
  542. };
  543.  
  544. ##############################################################################
  545. #
  546. # Set the subplot, this overides the action in plot().
  547. #
  548.  
  549. subplot = function ( sub )
  550. {
  551.   check_plot_object ();
  552.   
  553.   if (!exist (sub))
  554.   {
  555.     subplot_f = 0;
  556.     _pladv (0);
  557.   else
  558.     if (sub > WIN.[P].nplot)
  559.     {
  560.       error ("Current window does not have this many subplots");
  561.     }
  562.     if (sub > 0)
  563.     {
  564.       WIN.[P].subplot = sub - 1;
  565.       subplot_f = 1;
  566.       _pladv (sub);
  567.     else
  568.       if (sub == 0)
  569.       {
  570.         # Do not advance, stay at current subplot
  571.         WIN.[P].subplot = WIN.[P].subplot - 1;
  572.         subplot_f = 1;
  573.       }
  574.     }
  575.   }
  576. };
  577.  
  578. ##############################################################################
  579. #
  580. # Plot the columns of a matrix (X-Y plot).
  581. #
  582. ##############################################################################
  583.  
  584. plot = function ( data, key, textf )
  585. {
  586.   check_plot_object ();
  587.   
  588.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  589.   if (!exist (key)) { key = 1; }
  590.   if (!exist (textf)) { textf = 1; }
  591.  
  592.   #
  593.   # Draw the graph
  594.   # Step through the matrix plotting
  595.   # each column versus the 1st
  596.   #
  597.   
  598.   if (class (data) == "num")
  599.   {
  600.     #
  601.     # Set up the plot basics
  602.     #
  603.  
  604.     if (abs (key) > data.nc)
  605.     {
  606.       error_1 ("plot: KEY argument > M.nc");
  607.     }
  608.     
  609.     _plgra ();
  610.     _plcol (1);
  611.     _pllsty (1);
  612.     _plfont (WIN.[P].font[p]);
  613.     _plwid (WIN.[P].width[p]);
  614.  
  615.     if (!subplot_f) 
  616.     {
  617.       _pladv (0);        # Advance 1 subplot
  618.     else
  619.       subplot_f = 0;     # The user has set the subplot
  620.     }
  621.  
  622.     if (WIN.[P].aspect[p] != 0)
  623.     {
  624.       _plvasp (WIN.[P].aspect[p]);
  625.     else
  626.       _plvsta ();
  627.     }
  628.     
  629.     #
  630.     # Compute scale limits
  631.     #
  632.  
  633.     k = find ((1:data.nc) != abs (key));
  634.     if (key > 0)
  635.     {
  636.       if (data.nc != 1)
  637.       {
  638.     x_scales ( real(data)[;key], p, xmin, xmax );
  639.     y_scales ( real(data)[;k],   p, ymin, ymax );
  640.       else
  641.     x_scales ( (1:data.nr)', p, xmin, xmax );
  642.     y_scales ( real(data),   p, ymin, ymax );
  643.       }
  644.     else if (key < 0) {
  645.       x_scales ( real(data)[;k],   p, xmin, xmax );
  646.       y_scales ( real(data)[;abs(key)], p, ymin, ymax );
  647.     else
  648.       x_scales ( (1:data.nr)', p, xmin, xmax );
  649.       y_scales ( real(data),   p, ymin, ymax );
  650.     } }
  651.  
  652.     _plwind (xmin, xmax, ymin, ymax);
  653.     _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  654.     if (plot_matrix ( data, key, p, 0, xmin, xmax, ymin, ymax, ymax-ymin ) < 0) 
  655.     {
  656.       return -1;
  657.     }
  658.     
  659.     else if (class (data) == "list") {
  660.       
  661.       _plgra ();
  662.       _plcol (1);
  663.       _pllsty (1);
  664.       _plfont (WIN.[P].font[p]);
  665.       _plwid (WIN.[P].width[p]);
  666.  
  667.       list_scales ( data, key, p, xmin, xmax, ymin, ymax );
  668.  
  669.       if (!subplot_f) 
  670.       {
  671.     _pladv (0);        # Advance 1 subplot
  672.       else
  673.     subplot_f = 0;     # The user has set the subplot
  674.       }
  675.  
  676.       if (WIN.[P].aspect[p] != 0)
  677.       {
  678.     _plvasp (WIN.[P].aspect[p]);
  679.       else
  680.        _plvsta ();
  681.       }
  682.       
  683.       _plwind (xmin, xmax, ymin, ymax);
  684.       _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  685.       if (plot_list ( data, key, p, xmin, xmax, ymin, ymax ) < 0) 
  686.       { 
  687.     return -1;
  688.       }
  689.  
  690.     else
  691.       error ("plot: un-acceptable argument");
  692.   } }
  693.  
  694.   _pllsty (1);
  695.   _plcol (1);
  696.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  697.   _plflush ();
  698.   if (textf)
  699.   {
  700.     _pltext ();
  701.   }
  702.   
  703.   #
  704.   # Increment the plot no. so that next time
  705.   # we use the correct settings.
  706.   #
  707.   
  708.   WIN.[P].subplot = WIN.[P].subplot + 1;
  709.   return P;
  710. };
  711.  
  712. #
  713. # plhold:
  714. # Plot some data, and "hold" on for more.
  715. # Plot the data, setting up the plot as usual the first time.
  716. # On subsequent plots do not do any setup, just plot some
  717. # more. plhold_off must be called to finish up.
  718. #
  719.  
  720. plhold_first = 1;    # True (1) if plhold() has NOT been used.
  721.                         # Or if plhold_off() has been used.
  722.             # False (0) if plhold is in use
  723.  
  724. static (hxmin, hxmax, hymin, hymax)
  725.  
  726. plhold = function ( data, key )
  727. {
  728.   check_plot_object ();
  729.   
  730.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  731.   if (!exist (key)) { key = 1; }
  732.   if (abs (key) > data.nc)
  733.   {
  734.     error_1 ("plot: KEY argument > M.nc");
  735.   }
  736.   
  737.   if (plhold_first)
  738.   {
  739.     if (class (data) == "num")
  740.     {
  741.       #
  742.       # Do the setup ONCE
  743.       #
  744.       hxmin = hxmax = hymin = hymax = 0;
  745.       _plgra ();
  746.       _plcol (1);
  747.       _pllsty (1);
  748.       _plfont (WIN.[P].font[p]);
  749.       _plwid (WIN.[P].width[p]);
  750.  
  751.       if (!subplot_f) 
  752.       {
  753.     _pladv (0);        # Advance 1 subplot
  754.       else
  755.     subplot_f = 0;     # The user has set the subplot
  756.       }
  757.  
  758.       if (WIN.[P].aspect[p] != 0)
  759.       {
  760.     _plvasp (WIN.[P].aspect[p]);
  761.       else
  762.     _plvsta ();
  763.       }
  764.  
  765.       xy_scales ( real(data), p, hxmin, hxmax, hymin, hymax );
  766.       
  767.       k = find ((1:data.nc) != abs (key));
  768.       if (key > 0)
  769.       {
  770.     x_scales ( real(data)[;key], p, xmin, xmax );
  771.     if (data.nc != 1)
  772.     {
  773.       y_scales ( real(data)[;k],   p, ymin, ymax );
  774.         else
  775.       y_scales ( (1:data.nr)',   p, ymin, ymax );
  776.     }
  777.       else if (key < 0) {
  778.     x_scales ( real(data)[;k],   p, xmin, xmax );
  779.     y_scales ( real(data)[;abs(key)], p, ymin, ymax );
  780.       else
  781.     x_scales ( (1:data.nr)', p, xmin, xmax );
  782.     y_scales ( real(data),   p, ymin, ymax );
  783.       } }
  784.  
  785.       _plwind (hxmin, hxmax, hymin, hymax);
  786.       _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  787.       _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);
  788.     else
  789.       error ("plot: un-acceptable argument");
  790.     }
  791.     plhold_first = 0;
  792.   }
  793.   
  794.   if (plot_matrix ( data, key, p, 0, hxmin, hxmax, hymin, hymax, hymax-hymin ) < 0) 
  795.   { 
  796.     return -1; 
  797.   }
  798.  
  799.   _plcol (1);
  800.   _plflush ();
  801.   _pltext ();
  802.  
  803.   return P;
  804. };
  805.  
  806. ##############################################################################
  807. #
  808. # Clean up the plotting environment and get ready
  809. # for normal interactive usage.
  810. #
  811.  
  812. plhold_off = function ( )
  813. {
  814.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  815.   plhold_first = 1;  
  816.   _plcol (1);
  817.   _plflush ();
  818.   _pltext ();
  819.   WIN.[P].subplot = WIN.[P].subplot + 1;
  820.   return P;
  821. };
  822.  
  823. ##############################################################################
  824. #
  825. # Plot a 3-Dimensional graph. The data is composed in a list, with
  826. # elements `x', `y', and `z'. x and y are single-dimension arrays
  827. # (row or column matrices), and z is a two-dimensional array. The
  828. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  829. # the array x can be thought of a "row-labels", and the values of y
  830. # can be thought of as "column-lables" for the 2-dimensioal array z.
  831. #
  832. # At present plot3 can plot 3 distinct lists. Each list may have
  833. # different X, Y, and Z scales.
  834. #
  835. ##############################################################################
  836.  
  837. plot3 = function ( L31, L32, L33 )
  838. {
  839.   check_plot_object ();
  840.  
  841.   #
  842.   # 1st check list contents
  843.   #
  844.   
  845.   if (exist (L31)) { check_3d_list (L31); }
  846.   if (exist (L32)) { check_3d_list (L32); }
  847.   if (exist (L33)) { check_3d_list (L33); }
  848.   
  849.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  850.  
  851.   #
  852.   # Figure out the scale limits. 
  853.   # Needs improvement!
  854.   #
  855.   
  856.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  857.   if (exist (L31)) 
  858.   {
  859.     XYZ_scales (L31.x, L31.y, L31.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  860.     xmin = Xmin; xmax = Xmax;
  861.     ymin = Ymin; ymax = Ymax;
  862.     zmin = Zmin; zmax = Zmax;
  863.   }
  864.   if (exist (L32)) 
  865.   {
  866.     XYZ_scales (L32.x, L32.y, L32.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  867.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  868.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  869.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  870.   }   
  871.   if (exist (L33)) 
  872.   {
  873.     XYZ_scales (L33.x, L33.y, L33.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  874.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  875.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  876.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  877.   }
  878.   
  879.   _plgra ();
  880.   _plcol (1);
  881.   _pllsty (1);
  882.   _plfont (WIN.[P].font[p]);
  883.   _plwid (WIN.[P].width[p]);
  884.   
  885.   # basex = 2; basey = 2; height = 4;
  886.   xmin2d = -2.0; xmax2d = 2.0;
  887.   ymin2d = -3.0; ymax2d = 5.0;
  888.   
  889.   _plenv (xmin2d, xmax2d, ymin2d, ymax2d, 0, -2);
  890.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  891.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  892.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  893.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  894.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  895.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  896.  
  897.   if (exist (L31))
  898.   {
  899.     if (find_char (WIN.[P].grid3x[p], "l"))
  900.     { x = log10 (real (L31.x)); else x = real (L31.x); }
  901.     if (find_char (WIN.[P].grid3y[p], "l"))
  902.     { y = log10 (real (L31.y)); else y = real (L31.y); }
  903.     if (find_char (WIN.[P].grid3z[p], "l"))
  904.     { z = log10 (real (L31.z)); else z = real (L31.z); }
  905.     
  906.     _plcol (2);
  907.     _plot3d (x, y, z, L31.x.n, L31.y.n, 3, 0);
  908.   }
  909.   if (exist (L32))
  910.   {
  911.     if (find_char (WIN.[P].grid3x[p], "l"))
  912.     { x = log10 (real (L32.x)); else x = real (L32.x); }
  913.     if (find_char (WIN.[P].grid3y[p], "l"))
  914.     { y = log10 (real (L32.y)); else y = real (L32.y); }
  915.     if (find_char (WIN.[P].grid3z[p], "l"))
  916.     { z = log10 (real (L32.z)); else z = real (L32.z); }
  917.     
  918.     _plcol (3);
  919.     _pllsty (2);
  920.     _plot3d (x, y, z, L32.x.n, L32.y.n, 3, 0);
  921.   }
  922.   if (exist (L33)) 
  923.   {
  924.     if (find_char (WIN.[P].grid3x[p], "l"))
  925.     { x = log10 (real (L33.x)); else x = real (L33.x); }
  926.     if (find_char (WIN.[P].grid3y[p], "l"))
  927.     { y = log10 (real (L33.y)); else y = real (L33.y); }
  928.     if (find_char (WIN.[P].grid3z[p], "l"))
  929.     { z = log10 (real (L33.z)); else z = real (L33.z); }
  930.     
  931.     _plcol (4);
  932.     _pllsty (3);
  933.     _plot3d (x, y, z, L33.x.n, L33.y.n, 3, 0);
  934.   }
  935.   
  936.   _plflush ();
  937.   _pltext ();
  938.   
  939.   #
  940.   # Increment the plot no. so that next time
  941.   # we use the correct settings.
  942.   #
  943.   
  944.   WIN.[P].subplot = WIN.[P].subplot + 1;
  945.   
  946.   return P;
  947. };
  948.  
  949. ##############################################################################
  950. #
  951. # Plot a 3-Dimensional graph. The data is composed in a list, with
  952. # elements `x', `y', and `z'. x and y are single-dimension arrays
  953. # (row or column matrices), and z is a two-dimensional array. The
  954. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  955. # the array x can be thought of a "row-labels", and the values of y
  956. # can be thought of as "column-lables" for the 2-dimensioal array z.
  957. #
  958. # At present plmesh can plot 3 distinct lists. Each list may have
  959. # different X, Y, and Z scales.
  960. #
  961. ##############################################################################
  962.  
  963. plmesh = function ( L31, L32, L33 )
  964. {
  965.   check_plot_object ();
  966.   
  967.   #
  968.   # 1st check list contents
  969.   #
  970.   
  971.   if (exist (L31)) { check_3d_list (L31); }
  972.   if (exist (L32)) { check_3d_list (L32); }
  973.   if (exist (L33)) { check_3d_list (L33); }
  974.   
  975.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  976.  
  977.   #
  978.   # Figure out the scale limits. 
  979.   # Needs improvement!
  980.   #
  981.   
  982.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  983.   if (exist (L31)) 
  984.   {
  985.     XYZ_scales (L31.x, L31.y, L31.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  986.     xmin = Xmin; xmax = Xmax;
  987.     ymin = Ymin; ymax = Ymax;
  988.     zmin = Zmin; zmax = Zmax;
  989.   }
  990.   if (exist (L32)) 
  991.   {
  992.     XYZ_scales (L32.x, L32.y, L32.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  993.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  994.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  995.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  996.   }   
  997.   if (exist (L33)) 
  998.   {
  999.     XYZ_scales (L33.x, L33.y, L33.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  1000.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  1001.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  1002.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  1003.   }
  1004.  
  1005.   _plgra ();
  1006.   _plcol (1);
  1007.   _pllsty (1);
  1008.   _plfont (WIN.[P].font[p]);
  1009.   _plwid (WIN.[P].width[p]);
  1010.   
  1011.   # basex = 2; basey = 2; height = 4;
  1012.   xmin2d = -2.0; xmax2d = 2.0;
  1013.   ymin2d = -3.0; ymax2d = 5.0;
  1014.   
  1015.   _plenv (xmin2d, xmax2d, ymin2d, ymax2d, 0, -2);
  1016.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  1017.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  1018.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  1019.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  1020.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  1021.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  1022.  
  1023.   if (exist (L31))
  1024.   {
  1025.     if (find_char (WIN.[P].grid3x[p], "l"))
  1026.     { x = log10 (real (L31.x)); else x = real (L31.x); }
  1027.     if (find_char (WIN.[P].grid3y[p], "l"))
  1028.     { y = log10 (real (L31.y)); else y = real (L31.y); }
  1029.     if (find_char (WIN.[P].grid3z[p], "l"))
  1030.     { z = log10 (real (L31.z)); else z = real (L31.z); }
  1031.     
  1032.     _plcol (2);
  1033.     _plmesh (x, y, z, L31.x.n, L31.y.n, 3);
  1034.   }
  1035.   if (exist (L32))
  1036.   {
  1037.     if (find_char (WIN.[P].grid3x[p], "l"))
  1038.     { x = log10 (real (L32.x)); else x = real (L32.x); }
  1039.     if (find_char (WIN.[P].grid3y[p], "l"))
  1040.     { y = log10 (real (L32.y)); else y = real (L32.y); }
  1041.     if (find_char (WIN.[P].grid3z[p], "l"))
  1042.     { z = log10 (real (L32.z)); else z = real (L32.z); }
  1043.     
  1044.     _plcol (3);
  1045.     _pllsty (2);
  1046.     _plmesh (x, y, z, L32.x.n, L32.y.n, 3);
  1047.   }
  1048.   if (exist (L33)) 
  1049.   {
  1050.     if (find_char (WIN.[P].grid3x[p], "l"))
  1051.     { x = log10 (real (L33.x)); else x = real (L33.x); }
  1052.     if (find_char (WIN.[P].grid3y[p], "l"))
  1053.     { y = log10 (real (L33.y)); else y = real (L33.y); }
  1054.     if (find_char (WIN.[P].grid3z[p], "l"))
  1055.     { z = log10 (real (L33.z)); else z = real (L33.z); }
  1056.     
  1057.     _plcol (4);
  1058.     _pllsty (3);
  1059.     _plmesh (x, y, z, L33.x.n, L33.y.n, 3);
  1060.   }
  1061.  
  1062.   _plflush ();
  1063.   _pltext ();
  1064.   
  1065.   #
  1066.   # Increment the plot no. so that next time
  1067.   # we use the correct settings.
  1068.   #
  1069.   
  1070.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1071.   
  1072.   return P;
  1073. };
  1074.  
  1075. ##############################################################################
  1076. #
  1077. # Plot contours. The data is composed in a list, with
  1078. # elements `x', `y', and `z'. x and y are single-dimension arrays
  1079. # (row or column matrices), and z is a two-dimensional array. The
  1080. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  1081. # the array x can be thought of a "row-labels", and the values of y
  1082. # can be thought of as "column-lables" for the 2-dimensioal array z.
  1083. #
  1084. ##############################################################################
  1085.  
  1086. plcont = function ( CL )
  1087. {
  1088.   check_plot_object ();
  1089.   
  1090.   #
  1091.   # 1st check list contents
  1092.   #
  1093.   
  1094.   if (exist (CL)) { check_3d_list (CL); }
  1095.  
  1096.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1097.   
  1098.   #
  1099.   # Figure out the scale limits. 
  1100.   # Needs improvement!
  1101.   #
  1102.  
  1103.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  1104.   if (exist (CL)) 
  1105.   {
  1106.     XYZ_scales (CL.x, CL.y, CL.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  1107.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  1108.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  1109.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  1110.   }
  1111.  
  1112.   _plgra ();
  1113.   _plcol (1);
  1114.   _pllsty (1);
  1115.   _plfont (WIN.[P].font[p]);
  1116.   _plwid (WIN.[P].width[p]);
  1117.  
  1118.   #
  1119.   # Set up the 1st viewport for drawing the plot.
  1120.   #
  1121.  
  1122.   if (!subplot_f) 
  1123.   {
  1124.     _pladv (0);        # Advance 1 subplot
  1125.   else
  1126.     subplot_f = 0;     # The user has set the subplot
  1127.   }
  1128.  
  1129.   _plvpas (0.15, 0.75, 0.15, 0.85, WIN.[P].aspect[p]);
  1130.   # _plvpor (0.15, 0.75, 0.15, 0.85);
  1131.   _plwind (xmin, xmax, ymin, ymax);
  1132.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1133.  
  1134.   # Convert the data to log data if necessary.
  1135.   if (find_char (WIN.[P].gridx[p], "l"))
  1136.   { x = log10 (real (CL.x)); else x = real (CL.x); }
  1137.   if (find_char (WIN.[P].gridy[p], "l"))
  1138.   { y = log10 (real (CL.y)); else y = real (CL.y); }
  1139.   z = real (CL.z);
  1140.   
  1141.   if (exist (CL.clevel))
  1142.   {
  1143.     clevel = CL.clevel;
  1144.   else
  1145.     clevel = linspace(zmin, zmax, 10);
  1146.   }
  1147.  
  1148.   #
  1149.   # Draw the contours
  1150.   #
  1151.  
  1152.   l = 1;
  1153.   for (i in 1:clevel.n)
  1154.   {
  1155.     k = mod (i-1, 14) + 1;
  1156.     j = mod (i-1, 8) + 1;
  1157.     _pllsty(j);
  1158.     _plcol (1+k);
  1159.     if (_plcont (x, y, z, 1, CL.x.n, 1, CL.y.n, clevel[i]))
  1160.     {
  1161.       llevel[l] = clevel[i];
  1162.       l = l + 1;
  1163.     }
  1164.   }
  1165.  
  1166.   #
  1167.   # Reset color and draw the labels.
  1168.   #
  1169.  
  1170.   _plcol (1);
  1171.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1172.  
  1173.   #
  1174.   # Draw the contour legend. Use a new viewport to the right
  1175.   # of the contour plot.
  1176.   #
  1177.  
  1178.   #_plvpas (0.75, 1.0, 0.15, 0.85, WIN.[P].aspect[p]);
  1179.   _plvpor (0.75, 1.0, 0.15, 0.85);
  1180.   _plwind (0, 1, 0, 1);
  1181.  
  1182.   v = 1 - 1/(2*llevel.n);
  1183.  
  1184.   for (i in 1:llevel.n)
  1185.   {
  1186.     xl = [0.1, 0.2, 0.3]';
  1187.     yl = [v, v, v]';
  1188.     v = v - 1/llevel.n;
  1189.  
  1190.     k = mod (i-1, 14) + 1;
  1191.     j = mod (i-1, 8) + 1;
  1192.  
  1193.     _plcol (1+k);
  1194.     _pllsty (j);
  1195.  
  1196.     _plline (3, xl, yl);
  1197.     sprintf (stmp, "%.2g", llevel[i]);
  1198.     plptex (stmp, xl[3]+.1, yl[3], , , 0);
  1199.   }
  1200.  
  1201.   # Flush  and go back to text mode.
  1202.   _plflush ();
  1203.   _pltext ();
  1204.   
  1205.   #
  1206.   # Increment the plot no. so that next time
  1207.   # we use the correct settings.
  1208.   #
  1209.   
  1210.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1211.   
  1212.   return P;
  1213. };
  1214.  
  1215. ##############################################################################
  1216. #
  1217. # Plot 3-D lines, etc...
  1218. #
  1219.  
  1220. pl3d = function ( X, Y, Z, BR )
  1221. {
  1222.   local (X, Y, Z, BR)
  1223.   check_plot_object ();
  1224.   
  1225.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1226.  
  1227.   #
  1228.   # Some basic checks
  1229.   #
  1230.  
  1231.   if ((N = X.n) != Y.n) { error ("pl3d: X and Y must have same length"); }
  1232.   if (N != Z.n) { error ("pl3d: X and Z must have same length"); }
  1233.  
  1234.   if (!exist (BR)) { BR = N; }
  1235.   if (mod (N, BR) != 0) { error ("pl3d: X.n must be divisible by BR"); }
  1236.   iBR = int (N / BR);
  1237.   if (iBR == 1) { k = N; else k = BR; }
  1238.  
  1239.   #
  1240.   # Figure out the scale limits. 
  1241.   # Needs improvement!
  1242.   #
  1243.   
  1244.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  1245.   XYZ_scales (X, Y, Z, p, xmin, xmax, ymin, ymax, zmin, zmax);
  1246.  
  1247.   _plgra ();
  1248.   _plcol (1);
  1249.   _pllsty (1);
  1250.   _plfont (WIN.[P].font[p]);
  1251.   _plwid (WIN.[P].width[p]);
  1252.   
  1253.   if (!subplot_f) 
  1254.   {
  1255.     _pladv (0);        # Advance 1 subplot
  1256.     else
  1257.     subplot_f = 0;     # The user has set the subplot
  1258.   }
  1259.  
  1260.   if (find_char (WIN.[P].grid3x[p], "l"))
  1261.   { X = log10 (real (X)); else X = real (X); }
  1262.   if (find_char (WIN.[P].grid3y[p], "l"))
  1263.   { Y = log10 (real (Y)); else Y = real (Y); }
  1264.   if (find_char (WIN.[P].grid3z[p], "l"))
  1265.   { Z = log10 (real (Z)); else Z = real (Z); }
  1266.     
  1267.   # basex = 2; basey = 2; height = 4;
  1268.   xmin2d = -2.0; xmax2d = 2.0;
  1269.   ymin2d = -3.0; ymax2d = 5.0;
  1270.   
  1271.   _plvasp (WIN.[P].aspect[p]);
  1272.   _plwind (xmin2d, xmax2d, ymin2d, ymax2d);
  1273.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  1274.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  1275.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  1276.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  1277.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  1278.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  1279.  
  1280.   _plcol (2);
  1281.   for (i in 1:iBR)
  1282.   {
  1283.     j = [(i-1)*k+1:i*k];
  1284.     _plline3 (k, X[j], Y[j], Z[j]);
  1285.   }
  1286.   _plflush ();
  1287.   _pltext ();
  1288.   
  1289.   #
  1290.   # Increment the plot no. so that next time
  1291.   # we use the correct settings.
  1292.   #
  1293.   
  1294.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1295.   
  1296.   return P;
  1297. };
  1298.  
  1299. ##############################################################################
  1300. #
  1301. # error bar plot
  1302. #
  1303.  
  1304. plerry = function (x, y, y_low, y_high)
  1305. {
  1306.   check_plot_object ();
  1307.   
  1308.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1309.   WIN.[P].desc.[p] = 1j;    // use own legend
  1310.   
  1311.   if (x.nr != y.nr || x.nr != y_low.nr || x.nr != y_high.nr) 
  1312.   {
  1313.     error(" Size inconsistent in plerry.");
  1314.   }
  1315.   _plgra ();
  1316.   _plcol (1);
  1317.   _pllsty (1);
  1318.   _plfont (WIN.[P].font[p]);
  1319.   _plwid (WIN.[P].width[p]);
  1320.   xy_scales ( real([x,y,y_low,y_high]), p, xmin, xmax, ymin, ymax );
  1321.   
  1322.   if (!subplot_f) 
  1323.   {
  1324.     _pladv (0);        # Advance 1 subplot
  1325.   else
  1326.     subplot_f = 0;     # The user has set the subplot
  1327.   }
  1328.  
  1329.   if (WIN.[P].aspect[p] != 0)
  1330.   {
  1331.     _plvasp (WIN.[P].aspect[p]);
  1332.   else
  1333.     _plvsta ();
  1334.   }
  1335.  
  1336.   _plwind (xmin, xmax, ymin, ymax);
  1337.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1338.  
  1339.   if (plot_matrix ( [x,y], p, 0, xmin, xmax, ymin, ymax, ymax-ymin ) < 0) 
  1340.   { 
  1341.     return -1; 
  1342.   }
  1343.  
  1344.   _plcol (3);
  1345.   _plerry(x.nr, x, y_low, y_high);
  1346.   _plcol (1);
  1347.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1348.   _plflush ();
  1349.   _pltext ();
  1350.   
  1351.   #
  1352.   # Increment the plot no. so that next time
  1353.   # we use the correct settings.
  1354.   #
  1355.   
  1356.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1357.   return P;      
  1358. };
  1359.  
  1360. ##############################################################################
  1361. #
  1362. # Plot a Histogram(s), from the columns of a matrix.
  1363. #
  1364. ##############################################################################
  1365.  
  1366. plhist = function ( M , nbin )
  1367. {
  1368.   check_plot_object ();
  1369.   
  1370.   if (!exist (nbin)) { nbin = 10; }
  1371.   
  1372.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1373.   np = M.nr;
  1374.   
  1375.   # Compute max/min values of data
  1376.   
  1377.   ymin = min (min (real (M)));
  1378.   ymax = max (max (real (M)));
  1379.   
  1380.   #
  1381.   # Check computed scale limits against user's
  1382.   #
  1383.   
  1384.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  1385.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  1386.  
  1387.   _plgra ();
  1388.   _plcol (1);
  1389.   _plfont (WIN.[P].font[p]);
  1390.   _plwid (WIN.[P].width[p]);
  1391.   
  1392.   for (i in 1:M.nc) 
  1393.   { 
  1394.     hscale[i] = hist_scales (M[;i], nbin);
  1395.   }  
  1396.  
  1397.   if (!subplot_f) {
  1398.     _pladv (0);        # Advance 1 subplot
  1399.   else
  1400.     subplot_f = 0;     # The user has set the subplot
  1401.   }
  1402.  
  1403.   if (WIN.[P].aspect[p] != 0)
  1404.   {
  1405.     _plvasp (WIN.[P].aspect[p]);
  1406.   else
  1407.     _plvsta ();
  1408.   }
  1409.  
  1410.   _plwind (ymin, ymax, 0, max (hscale));
  1411.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1412.  
  1413.   v = max (hscale);
  1414.   xmax = ymax;
  1415.   for (i in 1:M.nc)
  1416.   {
  1417.     k = mod (i, 14) + 1;
  1418.     _plcol (WIN.[P].color[p;k]);
  1419.     _plhist (np, real(M[;i]), ymin, ymax, nbin, 1);
  1420.     
  1421.     if (!any (any (WIN.[P].desc.[p] == 1j)))
  1422.     {
  1423.       # Use the default if necessary
  1424.       if (WIN.[P].desc.[p][1] == "default") 
  1425.       {
  1426.     desc = "c"+num2str(i);
  1427.       else if (WIN.[P].desc.[p].n >= i) {
  1428.     desc = WIN.[P].desc.[p][i];
  1429.       else
  1430.     # Not sure what to do, user has messed up.
  1431.     desc = "";
  1432.       } }
  1433.  
  1434.       v = v - max(hscale)/11;
  1435.       xl = (ymax-ymin)*[10.5/12, 11/12, 11.5/12]' + ymin;
  1436.       yl = [v, v, v]';
  1437.  
  1438.       _plline (3, xl, yl);
  1439.       plptex(desc, xl[1]-(ymax-ymin)/25, yl[3], , , 1);
  1440.     }
  1441.   }
  1442.  
  1443.   _plcol (1);
  1444.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1445.   _plflush ();
  1446.   _pltext ();
  1447.  
  1448.   #
  1449.   # Increment the plot no. so that next time
  1450.   # we use the correct settings.
  1451.   #
  1452.   
  1453.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1454.  
  1455.   return 1;
  1456. };
  1457.  
  1458. ##############################################################################
  1459. #
  1460. # Various support functions for the WIN list
  1461. #
  1462. ##############################################################################
  1463.  
  1464. #
  1465. # Replot
  1466. #
  1467.  
  1468. replot = function ( )
  1469. {
  1470.   check_plot_object ();
  1471.   _replot ();
  1472. };
  1473.  
  1474. ##############################################################################
  1475. #
  1476. # Set the X-axis label
  1477. #
  1478.  
  1479. xlabel = function ( xstr )
  1480. {
  1481.   check_plot_object ();
  1482.   if (!exist (xstr)) { xstr = ""; }
  1483.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1484.   WIN.[P].xlabel[i] = xstr;
  1485. };
  1486.  
  1487. ##############################################################################
  1488. #
  1489. # Set the Y-axis label
  1490. #
  1491.  
  1492. ylabel = function ( xstr )
  1493. {
  1494.   check_plot_object ();
  1495.   if (!exist (xstr)) { xstr = ""; }
  1496.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1497.   WIN.[P].ylabel[i] = xstr;
  1498. };
  1499.  
  1500. ##############################################################################
  1501. #
  1502. # Set the Z-axis label
  1503. #
  1504.  
  1505. zlabel = function ( xstr )
  1506. {
  1507.   check_plot_object ();
  1508.   if (!exist (xstr)) { xstr = ""; }
  1509.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1510.   WIN.[P].zlabel[i] = xstr;
  1511. };
  1512.  
  1513. ##############################################################################
  1514. #
  1515. # Set the plot-title
  1516. #
  1517.  
  1518. ptitle = function ( xstr )
  1519. {
  1520.   check_plot_object ();
  1521.   if (!exist (xstr)) { xstr = ""; }
  1522.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1523.   WIN.[P].title[p] = xstr;
  1524. };
  1525.  
  1526. ##############################################################################
  1527. #
  1528. # Set the scale limits.
  1529. #
  1530.  
  1531. plimits = function ( xmin, xmax, ymin, ymax, zmin, zmax )
  1532. {
  1533.   check_plot_object ();
  1534.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1535.  
  1536.   if (exist (xmin)) 
  1537.   {
  1538.     WIN.[P].xmin[i] = xmin;
  1539.   else
  1540.     WIN.[P].xmin[i] = 1j;
  1541.   }
  1542.   if (exist (xmax)) 
  1543.   { 
  1544.     WIN.[P].xmax[i] = xmax;
  1545.   else
  1546.     WIN.[P].xmax[i] = 1j;
  1547.   }
  1548.  
  1549.   if (exist (ymin)) 
  1550.   {
  1551.     WIN.[P].ymin[i] = ymin;
  1552.   else
  1553.     WIN.[P].ymin[i] = 1j;
  1554.   }
  1555.   if (exist (ymax)) 
  1556.   {
  1557.     WIN.[P].ymax[i] = ymax;
  1558.   else
  1559.     WIN.[P].ymax[i] = 1j;
  1560.   }
  1561.  
  1562.   if (exist (zmin)) 
  1563.   {
  1564.     WIN.[P].zmin[i] = zmin;
  1565.   else
  1566.     WIN.[P].zmin[i] = 1j;
  1567.   }
  1568.   if (exist (zmax)) 
  1569.   {
  1570.     WIN.[P].zmax[i] = zmax;
  1571.   else
  1572.     WIN.[P].zmax[i] = 1j;
  1573.   }
  1574. };
  1575.  
  1576. ##############################################################################
  1577. #
  1578. # Set 2-D grid styles. A not-so-friendly interface.
  1579. #
  1580.  
  1581. plgrid = function ( sty_x, sty_y )
  1582. {
  1583.   check_plot_object ();
  1584.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1585.  
  1586.   if (exist (sty_x)) 
  1587.   { 
  1588.     if (class (sty_x) == "string")
  1589.     {
  1590.       WIN.[P].gridx[i] = sty_x;
  1591.     else
  1592.       error ("plgrid: requires string argument GRID_STY_X");
  1593.     }
  1594.   else
  1595.     WIN.[P].gridx[i] = grid_x_default;
  1596.   }
  1597.   if (exist (sty_y)) 
  1598.   { 
  1599.     if (class (sty_y) == "string")
  1600.     {
  1601.       WIN.[P].gridy[i] = sty_y;
  1602.     else
  1603.       error ("plgrid: requires string argument GRID_STY_Y");
  1604.     }
  1605.   else
  1606.     WIN.[P].gridy[i] = grid_y_default;
  1607.   }
  1608. };
  1609.  
  1610. ##############################################################################
  1611. #
  1612. # Set 3-D grid (axis) styles
  1613. #
  1614.  
  1615. plgrid3 = function ( sty_x, sty_y, sty_z )
  1616. {  
  1617.   check_plot_object ();
  1618.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1619.   if (exist (sty_x)) 
  1620.   { 
  1621.     if (class (sty_x) == "string")
  1622.     {
  1623.       WIN.[P].grid3x[i] = sty_x;
  1624.     else
  1625.       error ("plgrid3: requires string argument GRID_STY_X");
  1626.     }
  1627.   else
  1628.     WIN.[P].grid3x[i] = grid_3x_default;
  1629.   }
  1630.   if (exist (sty_y)) 
  1631.   { 
  1632.     if (class (sty_y) == "string")
  1633.     {
  1634.       WIN.[P].grid3y[i] = sty_y;
  1635.     else
  1636.       error ("plgrid3: requires string argument GRID_STY_Y");
  1637.     }
  1638.   else
  1639.     WIN.[P].grid3y[i] = grid_3y_default;
  1640.   }
  1641.   if (exist (sty_z)) 
  1642.   { 
  1643.     if (class (sty_z) == "string")
  1644.     {
  1645.       WIN.[P].grid3z[i] = sty_z;
  1646.     else
  1647.       error ("plgrid3: requires string argument GRID_STY_Z");
  1648.     }
  1649.   else
  1650.     WIN.[P].grid3z[i] = grid_3z_default;
  1651.   }
  1652. };
  1653.  
  1654. ##############################################################################
  1655. #
  1656. # A friendlier interface to changing 2-D grid/axis
  1657. # styles.
  1658. #
  1659.  
  1660. plaxis = function ( X_STR, Y_STR )
  1661. {
  1662.   check_plot_object ();
  1663.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1664.   
  1665.   if (exist (X_STR))
  1666.   {
  1667.     if (X_STR == "log") { WIN.[P].gridx[i] = "bcngstl"; }
  1668.   else
  1669.     WIN.[P].gridx[i] = grid_x_default;
  1670.   }
  1671.   
  1672.   if (exist (Y_STR))
  1673.   {
  1674.     if (Y_STR == "log") { WIN.[P].gridy[i] = "bcngstlv"; }
  1675.   else
  1676.     WIN.[P].gridy[i] = grid_y_default;
  1677.   }
  1678.   return P;
  1679. };
  1680.  
  1681. ##############################################################################
  1682. #
  1683. # Various internal support functions. Eventually these will be static.
  1684. #
  1685. ##############################################################################
  1686.  
  1687. #
  1688. # Find the X or Y scale limits .
  1689. # M can be a multi-column matrix, all columns
  1690. # will be used.
  1691. #
  1692.  
  1693. x_scales = function ( M, p, xmin, xmax )
  1694. {  
  1695.   #
  1696.   # 1st check for un-plottable data
  1697.   #
  1698.   
  1699.   if (any (any (isinf (M))))
  1700.   { error ("plot: cannot plot Infs"); }
  1701.   if (any (any (isnan (M))))
  1702.   { error ("plot: cannot plot NaNs"); }
  1703.   
  1704.   xmin = min (min (M));
  1705.   xmax = max (max (M));
  1706.   
  1707.   #
  1708.   # Check computed scale limits against user's
  1709.   #
  1710.   
  1711.   if (WIN.[P].xmin[p] != 1j) { xmin = WIN.[P].xmin[p]; }
  1712.   if (WIN.[P].xmax[p] != 1j) { xmax = WIN.[P].xmax[p]; }
  1713.  
  1714.   #
  1715.   # Check for potential errors
  1716.   #
  1717.   
  1718.   if (xmin == xmax) 
  1719.   { 
  1720.     # As good a guess as any
  1721.     xmin = xmin - 1;
  1722.     xmax = xmax + 1;
  1723.   }
  1724.   
  1725.   #
  1726.   # Finally, adjust if log-scales
  1727.   #
  1728.   
  1729.   if (find_char (WIN.[P].gridx[p], "l"))
  1730.   {
  1731.     if (xmin <= 0 || xmax <= 0) { error ("cannot plot log(x<=0)"); }
  1732.     xmin = log10 (xmin);
  1733.     xmax = log10 (xmax);
  1734.   }
  1735.   
  1736.   return 1;
  1737. };
  1738.  
  1739. y_scales = function ( M, p, xmin, xmax )
  1740. {
  1741.   
  1742.   #
  1743.   # 1st check for un-plottable data
  1744.   #
  1745.   
  1746.   if (any (any (isinf (M))))
  1747.   { error ("plot: cannot plot Infs"); }
  1748.   if (any (any (isnan (M))))
  1749.   { error ("plot: cannot plot NaNs"); }
  1750.   
  1751.   xmin = min (min (M));
  1752.   xmax = max (max (M));
  1753.   
  1754.   #
  1755.   # Check computed scale limits against user's
  1756.   #
  1757.   
  1758.   if (WIN.[P].ymin[p] != 1j) { xmin = WIN.[P].ymin[p]; }
  1759.   if (WIN.[P].ymax[p] != 1j) { xmax = WIN.[P].ymax[p]; }
  1760.  
  1761.   #
  1762.   # Check for potential errors
  1763.   #
  1764.   
  1765.   if (xmin == xmax) 
  1766.   { 
  1767.     # As good a guess as any
  1768.     xmin = xmin - 1;
  1769.     xmax = xmax + 1;
  1770.   }
  1771.   
  1772.   #
  1773.   # Finally, adjust if log-scales
  1774.   #
  1775.   
  1776.   if (find_char (WIN.[P].gridy[p], "l"))
  1777.   {
  1778.     if (xmin <= 0 || xmax <= 0) { error ("cannot plot log(y<=0)"); }
  1779.     xmin = log10 (xmin);
  1780.     xmax = log10 (xmax);
  1781.   }
  1782.   
  1783.   return 1;
  1784. };
  1785.  
  1786. z_scales = function ( M, p, xmin, xmax )
  1787. {
  1788.   
  1789.   #
  1790.   # 1st check for un-plottable data
  1791.   #
  1792.   
  1793.   if (any (any (isinf (M))))
  1794.   { error ("plot: cannot plot Infs"); }
  1795.   if (any (any (isnan (M))))
  1796.   { error ("plot: cannot plot NaNs"); }
  1797.   
  1798.   xmin = min (min (M));
  1799.   xmax = max (max (M));
  1800.   
  1801.   #
  1802.   # Check computed scale limits against user's
  1803.   #
  1804.   
  1805.   if (WIN.[P].zmin[p] != 1j) { xmin = WIN.[P].zmin[p]; }
  1806.   if (WIN.[P].zmax[p] != 1j) { xmax = WIN.[P].zmax[p]; }
  1807.  
  1808.   #
  1809.   # Check for potential errors
  1810.   #
  1811.   
  1812.   if (xmin == xmax) 
  1813.   { 
  1814.     # As good a guess as any
  1815.     xmin = xmin - 1;
  1816.     xmax = xmax + 1;
  1817.   }
  1818.   
  1819.   #
  1820.   # Finally, adjust if log-scales
  1821.   #
  1822.   
  1823.   if (find_char (WIN.[P].gridz[p], "l"))
  1824.   {
  1825.     if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log(z<=0)"); }
  1826.     xmin = log10 (xmin);
  1827.     xmax = log10 (xmax);
  1828.   }
  1829.   
  1830.   return 1;
  1831. };
  1832.  
  1833. ##############################################################################
  1834. #
  1835. # Find the X and Y scales for a single matrix. (OLD)
  1836. #
  1837.  
  1838. xy_scales = function ( M, p, xmin, xmax, ymin, ymax )
  1839. {  
  1840.   #
  1841.   # 1st check for un-plottable data
  1842.   #
  1843.   
  1844.   if (any (any (isinf (M))))
  1845.   { error ("plot: cannot plot infs"); }
  1846.   if (any (any (isnan (M))))
  1847.   { error ("plot: cannot plot NaNs"); }
  1848.   
  1849.   if (M.nc == 1)
  1850.   {
  1851.     xmin = 1;
  1852.     xmax = M.nr;
  1853.     ymin = min (M);
  1854.     ymax = max (M);
  1855.   else
  1856.     xmin = min (M[;1]);
  1857.     xmax = max (M[;1]);
  1858.     ymin = min (min (M[;2:M.nc]));
  1859.     ymax = max (max (M[;2:M.nc]));
  1860.   }
  1861.   
  1862.   #
  1863.   # Check computed scale limits against user's
  1864.   #
  1865.   
  1866.   if (WIN.[P].xmin[p] != 1j) { xmin = WIN.[P].xmin[p]; }
  1867.   if (WIN.[P].xmax[p] != 1j) { xmax = WIN.[P].xmax[p]; }
  1868.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  1869.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  1870.   
  1871.   #
  1872.   # Check for potential errors
  1873.   #
  1874.   
  1875.   if (xmin == xmax) 
  1876.   { 
  1877.     xmin = xmin - 1;
  1878.     xmax = xmax + 1;
  1879.   }
  1880.   
  1881.   if (ymin == ymax)
  1882.   {
  1883.     ymin = ymin - 1;
  1884.     ymax = ymax + 1;
  1885.   }
  1886.   
  1887.   #
  1888.   # Finally, adjust if log-scales
  1889.   #
  1890.   
  1891.   if (find_char (WIN.[P].gridx[p], "l"))
  1892.   {
  1893.     if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log <= 0"); }
  1894.     xmin = log10 (xmin);
  1895.     xmax = log10 (xmax);
  1896.   }
  1897.   if (find_char (WIN.[P].gridy[p], "l"))
  1898.   {
  1899.     if (ymin <= 0 || ymax <= 0) { error ("plot: cannot plot log <= 0"); }
  1900.     ymin = log10 (ymin);
  1901.     ymax = log10 (ymax);
  1902.   }
  1903.   
  1904.   return 1;
  1905. };
  1906.  
  1907. ##############################################################################
  1908. #
  1909. # Find the X, Y and Z scales for a single matrix.
  1910. #
  1911.  
  1912. XYZ_scales = function ( X, Y, Z, p, xmin, xmax, ymin, ymax, zmin, zmax )
  1913. {
  1914.   # X - scale
  1915.   if (any (any (isinf (X))))
  1916.   { error ("cannot plot infs"); }
  1917.   if (any (any (isnan (X))))
  1918.   { error ("cannot plot NaNs"); }
  1919.   
  1920.   xmin = min (real (X));
  1921.   xmax = max (real (X));
  1922.   
  1923.   # Y - scale
  1924.   if (any (any (isinf (Y))))
  1925.   { error ("cannot plot infs"); }
  1926.   if (any (any (isnan (Y))))
  1927.   { error ("cannot plot NaNs"); }
  1928.   
  1929.   ymin = min (real (Y));
  1930.   ymax = max (real (Y));
  1931.   
  1932.   # Z - scale
  1933.   if (any (any (isinf (Y))))
  1934.   { error ("cannot plot infs"); }
  1935.   if (any (any (isnan (Y))))
  1936.   { error ("cannot plot NaNs"); }
  1937.   
  1938.   zmin = min (min (real (Z)));
  1939.   zmax = max (max (real (Z)));
  1940.   
  1941.   #
  1942.   # Check computed scale limits against user's
  1943.   #
  1944.   
  1945.   if (WIN.[P].xmin[p] != 1j) { xmin = WIN.[P].xmin[p]; }
  1946.   if (WIN.[P].xmax[p] != 1j) { xmax = WIN.[P].xmax[p]; }
  1947.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  1948.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  1949.   if (WIN.[P].zmin[p] != 1j) { zmin = WIN.[P].zmin[p]; }
  1950.   if (WIN.[P].zmax[p] != 1j) { zmax = WIN.[P].zmax[p]; }
  1951.   
  1952.   #
  1953.   # Check for potential errors
  1954.   #
  1955.   
  1956.   if (xmin == xmax) 
  1957.   { 
  1958.     # As good a guess as any
  1959.     xmin = xmin - 1;
  1960.     xmax = xmax + 1;
  1961.   }
  1962.   
  1963.   if (ymin == ymax) 
  1964.   { 
  1965.     # As good a guess as any
  1966.     ymin = ymin - 1;
  1967.     ymax = ymax + 1;
  1968.   }
  1969.   
  1970.   if (zmin == zmax) 
  1971.   { 
  1972.     # As good a guess as any
  1973.     zmin = zmin - 1;
  1974.     zmax = zmax + 1;
  1975.   }
  1976.   
  1977.   #
  1978.   # Finally, adjust if log-scales
  1979.   #
  1980.   
  1981.   if (find_char (WIN.[P].grid3x[p], "l"))
  1982.   {
  1983.     if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log(x<=0)"); }
  1984.     xmin = log10 (xmin);
  1985.     xmax = log10 (xmax);
  1986.   }
  1987.   
  1988.   if (find_char (WIN.[P].grid3y[p], "l"))
  1989.   {
  1990.     if (ymin <= 0 || ymax <= 0) { error ("plot: cannot plot log(y<=0)"); }
  1991.     ymin = log10 (ymin);
  1992.     ymax = log10 (ymax);
  1993.   }
  1994.   
  1995.   if (find_char (WIN.[P].grid3z[p], "l"))
  1996.   {
  1997.     if (zmin <= 0 || zmax <= 0) { error ("plot: cannot plot log(z<=0)"); }
  1998.     zmin = log10 (zmin);
  1999.     zmax = log10 (zmax);
  2000.   }
  2001.   
  2002.   return 1;
  2003. };
  2004.  
  2005. ##############################################################################
  2006. #
  2007. # Find the X and Y scales for a list of matrices
  2008. #
  2009.  
  2010. list_scales = function ( data, key, p, Xmin, Xmax, Ymin, Ymax )
  2011. {
  2012.   once = 1;
  2013.   
  2014.   for (i in members (data))
  2015.   {
  2016.     M = real (data.[i]);
  2017.     if (class (M) != "num") { continue; }
  2018.     
  2019.     if (abs (key) > M.nc)
  2020.     {
  2021.       error_1 ("plot: KEY argument > M.nc");
  2022.     }
  2023.     
  2024.     #
  2025.     # 1st check for un-plottable data
  2026.     #
  2027.     
  2028.     if (any (any (isinf (M))))
  2029.     { error ("plot: cannot plot infs"); }
  2030.     if (any (any (isnan (M))))
  2031.     { error ("plot: cannot plot NaNs"); }
  2032.     
  2033.     k = find ((1:M.nc) != abs (key));
  2034.     if (key > 0)
  2035.     {
  2036.       if (M.nc != 1)
  2037.       {
  2038.     x_scales ( real(M)[;key], p, xmin, xmax );
  2039.     y_scales ( real(M)[;k],   p, ymin, ymax );
  2040.       else
  2041.     x_scales ( (1:M.nr)', p, xmin, xmax );
  2042.     y_scales ( real(M),   p, ymin, ymax );
  2043.       }
  2044.     else if (key < 0) {
  2045.       x_scales ( real(M)[;k],        p, xmin, xmax );
  2046.       y_scales ( real(M)[;abs(key)], p, ymin, ymax );
  2047.     else
  2048.       x_scales ( (1:M.nr)', p, xmin, xmax );
  2049.       y_scales ( real(M),   p, ymin, ymax );
  2050.     } }
  2051.  
  2052.     if (once) 
  2053.     { 
  2054.       Xmin = xmin; Xmax = xmax; Ymin = ymin; Ymax = ymax; 
  2055.       once = 0; 
  2056.     }
  2057.     if (xmin < Xmin) { Xmin = xmin; }
  2058.     if (xmax > Xmax) { Xmax = xmax; }
  2059.     if (ymin < Ymin) { Ymin = ymin; }
  2060.     if (ymax > Ymax) { Ymax = ymax; }
  2061.   }
  2062.   
  2063.   return 1;
  2064. };
  2065.  
  2066. ##############################################################################
  2067. #
  2068. # Find the maximum number of elements in a bin for a single 
  2069. # column matrix.
  2070. #
  2071.  
  2072. hist_scales = function ( data, nbin )
  2073. {
  2074.   dmin = min (real (data));
  2075.   dmax = max (real (data));
  2076.   dbin = linspace (dmin, dmax, nbin+1);
  2077.   binval = zeros (nbin, 1);
  2078.   
  2079.   for (i in 1:nbin)
  2080.   {
  2081.     binval[i] = length (find (data >= dbin[i] && data < dbin[i+1]));
  2082.   }
  2083.   
  2084.   return max (binval);
  2085. };
  2086.  
  2087. ##############################################################################
  2088. #
  2089. # Plot the columns of a matrix (core function)
  2090. #
  2091. # Notes: This is the core function for plotting a matrix. If the
  2092. # matrix is a single column, then the matrix elements are plotted
  2093. # versus the row numbers. If it is a multi-column matrix, then
  2094. # columns 2:N are plotted versus column 1.
  2095. #
  2096. # p, K, k and l are indices for plot features.
  2097. # p: the current plot index (the plot #)
  2098. # K: usually 0. This index is used to start of the line style and
  2099. # color index (k = color index, l = line-style index). This is mostly
  2100. # used by plot_list, which may call plot_matrix repeatedly.
  2101. # k: the line color index. This value determines the line color used
  2102. # for each column of data. If K = 0, then k goes like 2:14, then
  2103. # flops back to 1:14.
  2104. # l: the line style inex. This value determines the line style used
  2105. # for each column of data - not the line-type (points, or lines). If
  2106. # K = 0, then l goes like 2:8, then flops back to 1:8.
  2107. #
  2108. ##############################################################################
  2109.  
  2110. plot_matrix = function ( M, key, p, K, xmin, xmax, ymin, ymax, v )
  2111. {
  2112.   np = M.nr;
  2113.   
  2114.   if (M.nc == 1)
  2115.   {
  2116.     x = 1:M.nr;
  2117.     y = real (M);
  2118.     k = mod (1+K, 14) + 1;
  2119.     l = mod (1+K, 8);
  2120.     
  2121.     if (find_char (WIN.[P].gridx[p], "l"))
  2122.     { x = log10 (x); }
  2123.     if (find_char (WIN.[P].gridy[p], "l"))
  2124.     { y = log10 (y); }
  2125.     
  2126.     _plcol (WIN.[P].color[p;k]);
  2127.     _pllsty (WIN.[P].lstyle[p;l]);
  2128.     
  2129.     if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2130.     {
  2131.       _plline (M.nr, x, y);
  2132.     else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2133.       _plpoin (M.nr, x, y, WIN.[P].pstyle[p]+k);
  2134.     else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2135.       _plline (M.nr, x, y);
  2136.       _plpoin (M.nr, x, y, WIN.[P].pstyle[p]+k);
  2137.     else {
  2138.       _plline (M.nr, x, y);
  2139.     }}}}
  2140.  
  2141.     #
  2142.     # Now do the legend 
  2143.     #
  2144.     
  2145.     if (!any (any (WIN.[P].desc.[p] == 1j)))
  2146.     {
  2147.       # Use the default if necessary
  2148.       if (WIN.[P].desc.[p][1] == "default") 
  2149.       {
  2150.     desc = "c1";
  2151.       else if (WIN.[P].desc.[p].n >= k-1) {
  2152.     desc = WIN.[P].desc.[p][k-1];
  2153.       else
  2154.     # Not sure what to do, user has messed up.
  2155.     desc = "";
  2156.       } }
  2157.              
  2158.       v = v - (ymax-ymin)/11;
  2159.       xl = (xmax-xmin)*[10.5/12, 11/12, 11.5/12]' + xmin;
  2160.       yl = [v, v, v]' + ymin;
  2161.       
  2162.       if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2163.       {
  2164.     _plline (3, xl, yl);
  2165.       else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2166.     _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  2167.       else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2168.     _plline (3, xl, yl);
  2169.     _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  2170.       } } }
  2171.  
  2172.       plptex(desc, xl[1]-(xmax-xmin)/25, yl[3], , , 1);
  2173.       
  2174.     }
  2175.  
  2176.   else
  2177.  
  2178.     #
  2179.     # Check for large column dimension
  2180.     #
  2181.     
  2182.     if (M.nc > 3*M.nr)
  2183.     {
  2184.       printf (" Plot %i columns and %i rows, are you sure (y/n) ? "...
  2185.                , M.nc, M.nr);
  2186.       ans = getline ("stdin");
  2187.       if (ans.[1] != "y") { return -1; }
  2188.     }
  2189.     
  2190.     ki = find ((1:M.nc) != abs (key));
  2191.     for (i in ki)
  2192.     {
  2193.       if (key > 0)
  2194.       {
  2195.     x = real (M[;key]);
  2196.     y = real (M[;i]);
  2197.       else if (key < 0) {
  2198.     x = real (M[;i]);
  2199.     y = real (M[;abs(key)]);
  2200.       else
  2201.     x = (1:M.nr)';
  2202.     y = real (M[;i]);
  2203.       } }
  2204.  
  2205.       # Check for log scales, adjust if necessary
  2206.       if (find_char (WIN.[P].gridx[p], "l"))
  2207.       { x = log10 (x); }
  2208.       if (find_char (WIN.[P].gridy[p], "l"))
  2209.       { y = log10 (y); }
  2210.       
  2211.       k = mod (i-1 + K, 14) + 1;
  2212.       l = mod (8 + i-2 + K, 8) + 1;
  2213.       
  2214.       _plcol (WIN.[P].color[p;k]);
  2215.       _pllsty (WIN.[P].lstyle[p;l]);
  2216.       
  2217.       if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2218.       {
  2219.     _plline (np, x, y);
  2220.       else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2221.     _plpoin (np, x, y, WIN.[P].pstyle[p]+k);
  2222.       else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2223.     _plline (np, x, y);
  2224.     _plpoin (np, x, y, WIN.[P].pstyle[p]+k);
  2225.       else {
  2226.     _plline (np, x, y);
  2227.       }}}}
  2228.  
  2229.       #
  2230.       # Now do the legend 
  2231.       #
  2232.       
  2233.       if (!any (any (WIN.[P].desc.[p] == 1j)))
  2234.       {
  2235.     # Use the default if necessary
  2236.     if (WIN.[P].desc.[p][1] == "default") 
  2237.     {
  2238.       desc = "c" + num2str (i);
  2239.         else if (WIN.[P].desc.[p].n >= k-1) {
  2240.       desc = WIN.[P].desc.[p][k-1];
  2241.         else
  2242.       # Not sure what to do, user has messed up.
  2243.       desc = "";
  2244.         }}
  2245.              
  2246.     v = v - (ymax-ymin)/11;
  2247.     xl = (xmax-xmin)*[10.5/12, 11/12, 11.5/12]' + xmin;
  2248.     yl = [v, v, v]' + ymin;
  2249.     
  2250.     if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2251.     {
  2252.       _plline (3, xl, yl);
  2253.         else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2254.       _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  2255.         else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2256.       _plline (3, xl, yl);
  2257.       _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  2258.         }}}
  2259.     
  2260.     plptex(desc, xl[1]-(xmax-xmin)/25, yl[3], , , 1);
  2261.     
  2262.       }
  2263.     }
  2264.   }
  2265.   
  2266.   return k-1;
  2267. };
  2268.  
  2269. ##############################################################################
  2270. #
  2271. # Plot all of the matrices in a list on the same plot
  2272. #
  2273.  
  2274. plot_list = function ( L, key, p, xmin, xmax, ymin, ymax )
  2275. {
  2276.   k = 0;
  2277.   v = ymax - ymin;
  2278.   
  2279.   #
  2280.   # Sort out the list members
  2281.   #
  2282.  
  2283.   sl = list_sort (L);
  2284.  
  2285.   # Plot the list members with numeric labels 1st.
  2286.   if (exist (sl.num))
  2287.   {
  2288.     for (i in sl.num)
  2289.     {
  2290.       M = L.[i];
  2291.       if (class (M) != "num") { continue; }
  2292.       if ((k = plot_matrix (M, key, p, k, xmin, xmax, ymin, ymax, v)) < 0) 
  2293.       { 
  2294.     return k; 
  2295.       }
  2296.     }
  2297.   }
  2298.  
  2299.   # Now plot the list members with string labels.
  2300.   if (exist (sl.char))
  2301.   {
  2302.     for (i in sl.char)
  2303.     {
  2304.       M = L.[i];
  2305.       if (class (M) != "num") { continue; }
  2306.       if ((k = plot_matrix (M, key, p, k, xmin, xmax, ymin, ymax, v)) < 0) 
  2307.       { 
  2308.     return k; 
  2309.       }
  2310.     }
  2311.   }
  2312.   return 1;
  2313. };
  2314.  
  2315. ##############################################################################
  2316. #
  2317. # Check the elements of LIST.
  2318. # LIST must contain elements `x', `y',
  2319. # and `z'
  2320. #
  2321.  
  2322. check_3d_list = function ( LIST )
  2323. {
  2324.   #
  2325.   # Check existence and types
  2326.   #
  2327.   
  2328.   if (class (LIST) != "list") {
  2329.     error ("plot3: argument must be a list");
  2330.   }
  2331.   if (!exist (LIST.x)) {
  2332.     error ("plot3: arg must contain `x' member");
  2333.   else if (class (LIST.x) != "num") {
  2334.     error ("plot3: x must be numeric");
  2335.   } }
  2336.   if (!exist (LIST.y)) {
  2337.     error ("plot3: arg must contain `y' member");
  2338.   else if (class (LIST.y) != "num") {
  2339.     error ("plot3: y must be numeric"); 
  2340.   } }
  2341.   if (!exist (LIST.z)) {
  2342.     error ("plot3: arg must contain `z' member");
  2343.   else if (class (LIST.z) != "num") {
  2344.     error ("plot3: z must be numeric");
  2345.   } }
  2346.  
  2347.   #
  2348.   # Check sizes
  2349.   #
  2350.   
  2351.   if (LIST.x.n != LIST.z.nr) 
  2352.   {
  2353.     error ("plot3: x.n != z.nr");
  2354.   }
  2355.   
  2356.   if (LIST.y.n != LIST.z.nc) 
  2357.   {
  2358.     error ("plot3: y.n != z.nc");
  2359.   }
  2360.   
  2361. };
  2362.  
  2363. ##############################################################################
  2364. #
  2365. # A special type of histogram plot.
  2366. #
  2367.  
  2368. plhistx = function ( M , nbin )
  2369. {
  2370.   check_plot_object ();
  2371.   
  2372.   if (!exist (nbin)) { nbin = 10; }
  2373.   
  2374.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  2375.   np = M.nr;
  2376.   
  2377.   # Compute max/min values of data
  2378.   
  2379.   ymin = min (min(real (M)));
  2380.   ymax = max (max(real (M)));
  2381.   
  2382.   #
  2383.   # Check computed scale limits against user's
  2384.   #
  2385.   
  2386.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  2387.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  2388.   
  2389.   _plgra ();
  2390.   _plcol (15);
  2391.   _plfont (WIN.[P].font[p]);
  2392.   _plwid (WIN.[P].width[p]);
  2393.   
  2394.   dbin = (linspace (ymin, ymax, nbin+1))';
  2395.   for (j in 1:M.nc) 
  2396.   {
  2397.     // counting
  2398.     for (i in 1:nbin) 
  2399.     {
  2400.       binval[i;j] = length (find (M[;j] >= dbin[i] && M[;j] < dbin[i+1]));
  2401.     }
  2402.   }
  2403.   
  2404.   if (!subplot_f) {
  2405.     _pladv (0);        # Advance 1 subplot
  2406.   else
  2407.     subplot_f = 0;     # The user has set the subplot
  2408.   }
  2409.  
  2410.   if (WIN.[P].aspect[p] != 0)
  2411.   {
  2412.     _plvasp (WIN.[P].aspect[p]);
  2413.   else
  2414.     _plvsta ();
  2415.   }
  2416.  
  2417.   xmin = 0;
  2418.   xmax =  max(max(binval));
  2419.   _plwind (ymin, ymax, xmin, xmax);
  2420.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  2421.  
  2422.   #
  2423.   # Now reorganize dbin and binval so we plot points in
  2424.   # the middle of the bins.
  2425.   #
  2426.  
  2427.   delbin = abs(dbin[2] - dbin[1]);
  2428.   dbin = (linspace (ymin+delbin/2, ymax-delbin/2, nbin))';
  2429.   dbin = [ymin ; dbin ; ymax];
  2430.   binval = [zeros(1,binval.nc); binval; zeros(1,binval.nc)];
  2431.  
  2432.   v = xmax;
  2433.   for (i in 1:M.nc)
  2434.   {
  2435.     k = mod (i, 14) + 1;
  2436.     l = mod (i,  8) + 1;
  2437.     _plcol (WIN.[P].color[p;k]);
  2438.     _pllsty (WIN.[P].lstyle[p;l]);
  2439.     
  2440.     if      (get_style (WIN.[P].style.[p], k-1) == "line") 
  2441.     {
  2442.       _plline (nbin+2, dbin, binval[;i]);
  2443.     else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2444.       _plpoin (nbin+2, dbin, binval[;i], WIN.[P].pstyle[p]+k);
  2445.     else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2446.       _plline (nbin+2, dbin, binval[;i]);
  2447.       _plpoin (nbin+2, dbin, binval[;i], WIN.[P].pstyle[p]+k);     
  2448.     } } }
  2449.  
  2450.     // write legend around upper-right corner.
  2451.     // it is better to have user to choose location for legend.
  2452.     
  2453.     if (!any (any (WIN.[P].desc.[p] == 1j)))
  2454.     {
  2455.       # Use the default if necessary
  2456.       if (WIN.[P].desc.[p][1] == "default") 
  2457.       {
  2458.     desc = "c"+num2str(i);
  2459.       else if (WIN.[P].desc.[p].n >= i) {
  2460.       desc = WIN.[P].desc.[p][i];
  2461.       else
  2462.     # Not sure what to do, user has messed up.
  2463.     desc = "";
  2464.       } }
  2465.  
  2466.       v = v - (xmax)/11;
  2467.       xt = (ymax-ymin)*[10.5/12, 11/12, 11.5/12]' + ymin;
  2468.       yt = [v, v, v]';
  2469.       
  2470.       if      (get_style (WIN.[P].style.[p], k-1) == "line") 
  2471.       {
  2472.     _plline (3, xt, yt);
  2473.       else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2474.     _plpoin (3, xt, yt, WIN.[P].pstyle[p]+k);
  2475.       else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2476.     _plline (3, xt, yt);
  2477.     _plpoin (3, xt, yt, WIN.[P].pstyle[p]+k);
  2478.       } } }
  2479.  
  2480.       plptex(desc, xt[1]-(ymax-ymin)/25, yt[3], , , 1);
  2481.     }
  2482.   }
  2483.   
  2484.   _plcol (15);
  2485.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  2486.   _plflush ();
  2487.   _pltext ();
  2488.   
  2489.   #
  2490.   # Increment the plot no. so that next time
  2491.   # we use the correct settings.
  2492.   #
  2493.   
  2494.   WIN.[P].subplot = WIN.[P].subplot + 1;
  2495.   
  2496.   return 1;
  2497. };
  2498.  
  2499.  
  2500. ##############################################################################
  2501. #
  2502. # Create a legend in the current plot window
  2503. #
  2504. # if pobj.desc.[p] = inf()        no legend
  2505. # if pobj.desc.[p] = "default"        default ("c1", "c2", ...)
  2506. # if pobj.desc.[p] = "string"        use "string" as description
  2507. #
  2508.  
  2509. #
  2510. # Set the current plot legend string
  2511. #
  2512.  
  2513. plegend = function ( LEGEND )
  2514. {
  2515.   check_plot_object ();
  2516.   
  2517.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  2518.   
  2519.   if (!exist (LEGEND)) 
  2520.   {
  2521.     WIN.[P].desc.[p] = 1j;
  2522.     return P;
  2523.   }
  2524.   
  2525.   if (class (LEGEND) == "string")
  2526.   {
  2527.     WIN.[P].desc.[p] = LEGEND;
  2528.   }
  2529.   
  2530.   return P;
  2531. };
  2532.  
  2533. set3d = function (bx, by, h)
  2534. {
  2535.   if (!exist (bx)) { basex = 2; else basex = bx; }
  2536.   if (!exist (by)) { basey = 2; else basey = by; }
  2537.   if (!exist (h)) { height = 4; else height = h; }
  2538. };
  2539.